#ifndef PCPS_TIME_EVOLUTION_HEADER
#define PCPS_TIME_EVOLUTION_HEADER

#include <src/pcps.h>
#include <src/input.h>
#include <src/hamiltonian.h>
#include <src/operator.h>

namespace pcps {

  //--------------------------------------------------------------------------------
  // pcps::make_time_evolution_op -- Adds the contribution of a hamiltonian operator
  //                                 to one or more time evolution operators
  //--------------------------------------------------------------------------------

  template<class SCALAR, class PART, class OP>
  void make_time_evolution_op(const pcps::Input & userinp,
                              const typename pcps::OpBase<SCALAR>::const_ptr & op,
                              std::vector<int> & op_n_sites,
                              std::vector< boost::shared_array<   int> > & op_sites,
                              std::vector< boost::shared_array<SCALAR> > & op_matrices);

  //--------------------------------------------------------------------------------
  // pcps::get_time_evolution_ops -- Convert the hamiltonian's operators into the
  //                                 form used by the time evolution routine
  //--------------------------------------------------------------------------------

  template <class SCALAR, class PART>
  void get_time_evolution_ops(const pcps::Input & userinp,
                              const pcps::Hamiltonian<SCALAR> & ham,
                              std::vector<int> & op_n_sites,
                              std::vector< boost::shared_array<   int> > & op_sites,
                              std::vector< boost::shared_array<SCALAR> > & op_matrices);

  //--------------------------------------------------------------------------------
  // pcps::get_time_evolution_cluster -- Construct a cluster around a time evolution
  //                                     operator.
  //--------------------------------------------------------------------------------

  template <class SCALAR>
  void get_time_evolution_cluster(const pcps::Input & userinp,
                                  const pcps::Wavefunction<SCALAR> & wfn,
                                  const int op_n_sites,
                                  const int * const op_sites,
                                  const SCALAR * const op_matrices,
                                  boost::shared_ptr<std::vector<pcps::Correlator<SCALAR> > > & cluster_corrs,
                                  boost::shared_ptr<std::set<int> > & cluster_sites, 
                                  boost::shared_ptr<std::vector<int> > & cluster_offsets,
                                  int & n_clust_vars,
                                  int & n_clust_configs);

  //--------------------------------------------------------------------------------
  // pcps::time_evolution_driver -- evolves the wavefunction in either real or
  //                                imaginary time
  //--------------------------------------------------------------------------------

  template <class SCALAR>
  void time_evolution_driver(const pcps::Input & userinp,
                             const pcps::Hamiltonian<SCALAR> & ham,
                             pcps::Wavefunction<SCALAR> & wfn,
                             const bool real_time);

} // end namespace pcps

#endif
